################################################################################
#
#Copyright (c) 2011, Petr Skramovsky
#All rights reserved.
#
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#DISCLAIMED. IN NO EVENT SHALL Petr Skramovsky BE LIABLE FOR ANY
#DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
################################################################################

from bsp import FACE_TYPE_PATCH

class Vertex:
  def __init__(self, pos=None, tex=None, norm=None ):
    if pos == None:
      self.position = [0,0,0]
      self.texcoord = [[0,0],[0,0]]
      self.normal = [0,0,0]
    else:
      self.position = pos
      self.texcoord = tex
      self.normal = norm

  def __add__(self,a):
    v = Vertex()
    for i in range(0,3):
      v.position[i] = self.position[i] + a.position[i]
      v.normal[i] = self.position[i] + a.position[i]
    for i in range(0,2):
      for j in range(0,2):
        v.texcoord[i][j] = self.texcoord[i][j] + a.texcoord[i][j]
    return v

  def __mul__(self,a):
    v = Vertex()
    for i in range(0,3):
      v.position[i] = self.position[i] * a
      v.normal[i] = self.position[i] * a
    for i in range(0,2):
      for j in range(0,2):
        v.texcoord[i][j] = self.texcoord[i][j] * a
    return v

class Bezier:
  ctrl = [ Vertex() ] * 9
  verts = []
  num_verts = 0
  index = []
  
  def tessellate(self,L):
    L1 = L + 1
    self.num_verts = L1 * L1
    self.verts = [ Vertex() ] * self.num_verts
    for i in range(0,L1):
      a = float( i ) / float( L )
      b = 1.0 - a
      self.verts[i] = self.ctrl[ 0 ] * ( b * b ) + self.ctrl[3] * ( 2 * b * a ) + self.ctrl[ 6 ] * ( a * a )
    for i in range(0,L1):
      a = float( i ) / float( L )
      b = 1.0 - a
      temp = [ Vertex() ] * 3
      for j in range(0,3):
        k = 3 * j
        temp[j] = self.ctrl[k + 0] * (b * b) + self.ctrl[k + 1] * (2 * b * a) + self.ctrl[k + 2] * (a * a)
      for j in range(0,L1):
        a = float( j ) / float( L )
        b = 1.0 - a
        self.verts[i * L1 + j]=temp[0] * (b * b) +temp[1] * (2 * b * a) + temp[2] * (a * a)

    self.index = []
    for r in range(0,L):
      for c in range(0,L):
        self.index.append( ( r + 1 ) * L1 + c )
        self.index.append( r * L1 + c )
        self.index.append( r * L1 + c + 1 )

        self.index.append( ( r + 1 ) * L1 + c )
        self.index.append( r * L1 + c + 1 )
        self.index.append( ( r + 1 ) * L1 + c + 1 )



def get_bezier(m,f,l):
  patch_size_x = ( f.size[ 0 ] - 1 ) / 2;
  patch_size_y = ( f.size[ 1 ] - 1 ) / 2;
  num_bezier_patches = patch_size_y * patch_size_x;

  bezier = [ Bezier() for i in range( num_bezier_patches ) ]
  patch_index = 0
  for x in range(0,patch_size_x):
    for y in range(0,patch_size_y):
      index = 0
      for c in range(0,3):
        pos = c * f.size[0]
        i = f.vertex + 2 * x + f.size[0] * 2 * y + pos
        bezier[ patch_index ].ctrl[ index ] = Vertex(m.vertexes[i].position,m.vertexes[i].texcoord,m.vertexes[i].normal)
        index += 1;
        i += 1
        bezier[ patch_index ].ctrl[ index ] = Vertex(m.vertexes[i].position,m.vertexes[i].texcoord,m.vertexes[i].normal)
        index += 1;
        i += 1
        bezier[ patch_index ].ctrl[ index ] = Vertex(m.vertexes[i].position,m.vertexes[i].texcoord,m.vertexes[i].normal)
        index += 1;
      bezier[patch_index].tessellate(l)
      patch_index += 1
  return bezier
  
def get_patches(m,l):
  patches = []

  for f in m.faces :
    if f.type != FACE_TYPE_PATCH :
      continue

    bezier = get_bezier(m,f,l)
    patches.append( bezier )

  return patches
